#include <stdio.h>
// #include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
// #include <netdb.h>
#include <ifaddrs.h>
// #include <ifaddrs.h>
// #include <arpa/inet.h>
#include <net/if.h>  // 这里包含 IFF_LOOPBACK
#include <unistd.h>
#include <libssh/libssh.h>
#include <stdlib.h>

#include "../inc_path/writefiles.h"
#include "../inc_path/command.h"
#include "../inc_path/tools.h"


#define TEMP_DIR "/tmp/nancal"
#define FILES_PATH "/data/middlefiles-test-1"
#define MAX_SSH 3
#define MAX_NODES 3

// define NODE1
//#define NODE1_SENTINEL_CONF "home/aliee/test-files/node1/sentinel.conf"
//#define NODE1_REDIS_CONF "home/aliee/test-files/node1/redis.conf"
//#define NODE1_ROCKETMQ_CONF "home/aliee/test-files/node1/broker-n0.conf"
//#define NODE1_NACOS_CLUSTER_CONF "home/aliee/test-files/node1/cluster.conf"
//#define NODE1_NACOS_SERVER_CONF "home/aliee/test-files/node1/application.properties"
//#define NODE1_MINIO_SERVER_CONF "home/aliee/test-files/node1/miniod.service"
//#define NODE1_MINIO_ARGS_CONF "home/aliee/test-files/node1/miniod"
//// define NODE2
//#define NODE2_SENTINEL_CONF "home/aliee/test-files/node2/sentinel.conf"
//#define NODE2_REDIS_CONF "home/aliee/test-files/node2/redis.conf"
//#define NODE2_ROCKETMQ_CONF "home/aliee/test-files/node2/broker-n0.conf"
//#define NODE2_NACOS_CLUSTER_CONF "home/aliee/test-files/node2/cluster.conf"
//#define NODE2_NACOS_SERVER_CONF "home/aliee/test-files/node2/application.properties"
//#define NODE2_MINIO_SERVER_CONF "home/aliee/test-files/node2/miniod.service"
//#define NODE2_MINIO_ARGS_CONF "home/aliee/test-files/node2/miniod"
//// define NODE3
//#define NODE3_SENTINEL_CONF "home/aliee/test-files/node3/sentinel.conf"
//#define NODE3_REDIS_CONF "home/aliee/test-files/node3/redis.conf"
//#define NODE3_ROCKETMQ_CONF "home/aliee/test-files/node3/broker-n0.conf"
//#define NODE3_NACOS_CLUSTER_CONF "home/aliee/test-files/node3/cluster.conf"
//#define NODE3_NACOS_SERVER_CONF "home/aliee/test-files/node3/application.properties"
//#define NODE3_MINIO_SERVER_CONF "home/aliee/test-files/node3/miniod.service"
//#define NODE3_MINIO_ARGS_CONF "home/aliee/test-files/node3/miniod"

ssh_session my_ssh[MAX_SSH];
ssh_session ssssssss;
char new_node_ipaddr[MAX_NODES][64];

ssh_session init_ssh(const char *host, int port, const char *user, const char *password){
    int rc;
    ssh_session sshSession;
    // 配置连接参数
//    const char *host = "192.168.31.168";
//    int port = 22;
//    const char *user = "root";
//    const char *password = "nancal.123";

    // 初始化SSH会话
    sshSession = ssh_new();
    if (sshSession == NULL) exit(EXIT_FAILURE);

    ssh_options_set(sshSession, SSH_OPTIONS_HOST, host);
    ssh_options_set(sshSession, SSH_OPTIONS_PORT, &port);
    ssh_options_set(sshSession, SSH_OPTIONS_USER, user);

    // 连接服务器
    rc = ssh_connect(sshSession);
    if (rc != SSH_OK) {
        fprintf(stderr, "连接错误: %s\n", ssh_get_error(sshSession));
        ssh_free(sshSession);
        exit(EXIT_FAILURE);
    }

    // 密码认证
    rc = ssh_userauth_password(sshSession, NULL, password);
    if (rc != SSH_AUTH_SUCCESS) {
        fprintf(stderr, "认证失败: %s\n", ssh_get_error(sshSession));
        ssh_disconnect(sshSession);
        ssh_free(sshSession);
        exit(EXIT_FAILURE);
    }

    return sshSession;
}

int exec_remote_command(ssh_session sshSession, const char *command){

    // 执行示例命令
    printf("正在执行远程命令...\n");
    int rc = execute_remote_command(sshSession, command);
    if (rc != SSH_OK) {
        fprintf(stderr, "命令%s 执行失败\n", command);
        return EAI_FAIL;
    }

//
//    rc = execute_remote_command(sshSession, "echo 'hello aliee' > /hello.txt");
//    if (rc != SSH_OK) {
//        fprintf(stderr, "命令执行失败\n");
//    }
//    rc = execute_remote_command(sshSession, "ls -l /");
//    if (rc != SSH_OK) {
//        fprintf(stderr, "命令执行失败\n");
//    }
//
//    rc = execute_remote_command(sshSession, "mkdir -p /opt/nancal/base/{redis,nacos,rabbitmq,rocketmq,minio,nebula}");
//    if (rc != SSH_OK) {
//        fprintf(stderr, "命令%s 执行失败\n","mkdir -p /opt/nancal/base/{redis,nacos,rabbitmq,rocketmq,minio,nebula}");
//    }
//
//    rc = execute_remote_command(sshSession, "mkdir -p /opt/nancal/base/redis/{sentinel,logs}");
//    if (rc != SSH_OK) {
//        fprintf(stderr, "命令%s 执行失败\n","mkdir -p /opt/nancal/base/redis/{sentinel,logs}");
//    }
//
//
//    // 执行文件上传
//    const char *local_file;
//    sprintf(*local_file, "%s/node2/%s", FILES_PATH,)
//
//    const char *remote_file = "/远程/文件路径";

    // 清理资源
//    ssh_disconnect(sshSession);
//    ssh_free(sshSession);

    return EXIT_SUCCESS;
}

int main(int argc, char *argv[]) {
    // init ssh_session
//    my_ssh[0] = init_ssh("192.168.31.168", 22, "root", "nancal.123");
//    my_ssh[1] = init_ssh("192.168.31.99", 22, "root", "aliee.123");
//    my_ssh[2] = init_ssh("192.168.31.99", 22, "root", "nancal.123");

    int new_ipaddr_count = 0;
    // 根据传入的IP地址数量，初始化SSH会话
    if (argc == 3) {
        // 提供了一个IP地址 (argv[0]是程序名)
        printf("Initializing with 2 provided IPs: %s, %s\n", argv[1], argv[2]);
        my_ssh[0] = init_ssh(argv[1], 22, "root", argv[2]);
//        ssssssss = init_ssh(argv[1], 22, "root", argv[2]);
//        new_node_ipaddr[0] = argv[1];
        strcpy(new_node_ipaddr[0], argv[1]);
        new_ipaddr_count = 1;
    } else if (argc == 4) {
        // 提供了两个IP地址 (argv[0]是程序名)
        printf("Initializing with 2 provided IPs: %s, %s\n", argv[1], argv[2]);
        my_ssh[0] = init_ssh(argv[1], 22, "root", argv[3]);
        my_ssh[1] = init_ssh(argv[2], 22, "root", argv[3]);
//        new_node_ipaddr[0] = argv[1];
//        new_node_ipaddr[1] = argv[2];
        strcpy(new_node_ipaddr[0], argv[1]);
        strcpy(new_node_ipaddr[1], argv[2]);
        new_ipaddr_count = 2;
    } else if (argc == 5) {
        // 提供了三个IP地址
        printf("Initializing with 3 provided IPs: %s, %s, %s\n", argv[1], argv[2], argv[3]);
        my_ssh[0] = init_ssh(argv[1], 22, "root", argv[4]);
        my_ssh[1] = init_ssh(argv[2], 22, "root", argv[4]);
        // 注意：第三个节点的凭证可能需要修改
        my_ssh[2] = init_ssh(argv[3], 22, "root", argv[4]);
//        new_node_ipaddr[0] = argv[1];
//        new_node_ipaddr[1] = argv[2];
//        new_node_ipaddr[2] = argv[3];
        strcpy(new_node_ipaddr[0], argv[1]);
        strcpy(new_node_ipaddr[1], argv[2]);
        strcpy(new_node_ipaddr[2], argv[3]);
        new_ipaddr_count = 3;
    } else {
        // 参数数量不正确，打印帮助信息并退出
        fprintf(stderr, "Usage: %s <IP_ADDR_1> <IP_ADDR_2>\n", argv[0]);
        return 1; // 错误退出
    }


    createDir(TEMP_DIR);
    createDir(FILES_PATH);
    // create redis base Dir
    run_command_popen("mkdir -p /opt/nancal/base/{redis,nacos,rabbitmq,rocketmq,minio,nebula}", "create middlewares dir...");
    createDir("/opt/nancal/base/redis/sentinel");
    createDir("/opt/nancal/base/redis/logs");

    /* 2. 判断第 i 个槽位是否为空 */
    int rc;
    for (size_t i = 0; i < new_ipaddr_count; ++i) {
        if (my_ssh[i] == NULL) {
            printf("my_ssh[%zu] is empty\n", i);
        } else {
            printf("my_ssh[%zu] is in use (%p)\n", i, (void*)my_ssh[i]);
            rc = exec_remote_command(my_ssh[i],"mkdir -p /opt/nancal/base/{redis,nacos,rabbitmq,rocketmq,minio,nebula}");
            if (rc != EXIT_SUCCESS) {
                fprintf(stderr, "node %zu 命令%s 执行失败\n", i, "mkdir -p /opt/nancal/base/{redis,nacos,rabbitmq,rocketmq,minio,nebula}");
            }
            rc = exec_remote_command(my_ssh[i],"mkdir -p /opt/nancal/base/redis/{sentinel,logs}");
            if (rc != EXIT_SUCCESS) {
                fprintf(stderr, "node %zu 命令%s 执行失败\n", i, "mkdir -p /opt/nancal/base/redis/{sentinel,logs}");
            }
        }
    }


    // 新文件的路径
    const char *config_files = "/tmp/nancal/conf.tgz";
    // const char *sentinel_file = "/home/aliee/testfiles/sentinel.conf";

    struct ifaddrs *ifaddr, *ifa;
    char ipstr[INET_ADDRSTRLEN];
    char extract_tar_commands[256];

    int success = gen_files(config_files, "all");
    if (success != 0) {
        perror("Error writing to file");
        return -1;
    };

    printf("File written successfully to %s\n", config_files);

    // 获取本机所有网络接口的地址信息
    if (getifaddrs(&ifaddr) == -1) {
        perror("getifaddrs failed");
        return 1;
    }

    // 遍历所有网络接口
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        // 过滤掉回环接口（lo0/lo/docker0）
        if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_LOOPBACK) || strcmp(ifa->ifa_name, "docker0") == 0) {
            continue;
        }

        // 只处理 IPv4 地址
        if (ifa->ifa_addr->sa_family == AF_INET) {
            struct sockaddr_in *sa = (struct sockaddr_in *) ifa->ifa_addr;
            void *addr = &(sa->sin_addr);

            // 将 IP 地址从二进制格式转换为字符串格式
            if (inet_ntop(AF_INET, addr, ipstr, sizeof(ipstr)) != NULL) {
                printf("本机的IP地址是: %s (接口: %s)\n", ipstr, ifa->ifa_name);
            }
        }
    }

    // free memory
    freeifaddrs(ifaddr);

    // int result = system("sed -i 's/old_string/new_string/g' filename.txt");
    // run_command_popen("sed -i 's/old_string/new_string/g' filename.txt", "sed replace string...")

    snprintf(extract_tar_commands, 256,
             "tar -xf %s/conf.tgz -C %s",
             TEMP_DIR, FILES_PATH
    );
    run_command_popen(extract_tar_commands, "decompress tar file ...");

//    sprintf(comms[0], "sed -i 's/192.168.31.141/%s/g' /home/aliee/test-files/node1/sentinel.conf", ipstr);
//    printf("comms: %s\n", comms[0]);

//    sprintf(comms[1], "sed -i 's/192.168.31.141/%s/g' /home/aliee/testfiles/node1/redis.conf", ipstr);
//    printf("comms: %s\n", comms[1]);

//    sprintf(comms[2], "sed -i 's/192.168.31.141/%s/g' /home/aliee/testfiles/node1/broker-n0.conf", ipstr);


    // No longer use automatic acquisition of IP address. Instead, manually specify the IP addresses for the three machines.
//    ReplaceInfo rep_info = replaceStr("192.168.31.141", ipstr, argv[1]);

    // manually specify the IP addresses for the three machines.
    printf("before start replaceStr: \n");
//    sleep(30);
    ReplaceInfo rep_info = replaceStr(FILES_PATH, new_node_ipaddr, new_ipaddr_count, "all");
    printf("after start replaceStr: \n");
    // 获取数组中元素的个数
    int num_elements = sizeof(rep_info.comms) / sizeof(rep_info.comms[0]);

    // 输出数组中元素的个数
    printf("Array has %d elements.\n", num_elements);
//    strcpy(comms[2], "from C");
    printf("before start for : \n");
    printf("***************all comms_cnt %zu : \n", rep_info.comms_cnt);
    for (int i = 0; i < rep_info.comms_cnt; i++) {
        printf("comms: %s\n", rep_info.comms[i]);
        run_command_popen(rep_info.comms[i], "sed replace string...");
    }

    printf("start upload files123...\n");
//    int n = sizeof(rep_info.filesInfo) / sizeof(rep_info.filesInfo[0]); // 计算数组中元素的数量
    printf("start upload files456..., filesInfo num: %zu\n", rep_info.comms_cnt);

    for (int i = 0; i < rep_info.files_info_count; i++){
        printf("start upload files789...\n");
        // 执行文件上传
        // 计算所需内存大小（+3 用于斜杠和空终止符）
        printf("node_name: %s, file_name: %s \n", rep_info.filesInfo[i].node_name, rep_info.filesInfo[i].file_name);
        size_t local_len = strlen(FILES_PATH)
                           + strlen(rep_info.filesInfo[i].node_name)
                           + strlen(rep_info.filesInfo[i].file_name)
                           + 3;

        size_t remote_len = strlen(rep_info.filesInfo[i].remote_path)
                            + strlen(rep_info.filesInfo[i].file_name)
                            + 2;

// 分配内存
        char *local_file = malloc(local_len);
        char *remote_file = malloc(remote_len);
        // 检查分配结果
        if (!local_file || !remote_file) {
            free(local_file);
            free(remote_file);
            fprintf(stderr, "内存分配失败\n");
            exit(EXIT_FAILURE);
        }

        printf("start upload files10 11 12...\n");
        sprintf(local_file, "%s/%s/%s", FILES_PATH, rep_info.filesInfo[i].node_name,rep_info.filesInfo[i].file_name);
        sprintf(remote_file, "%s/%s",  rep_info.filesInfo[i].remote_path, rep_info.filesInfo[i].file_name);
        printf("start upload files13 14 15...\n");
//        const char *local_file = localFile;
//        const char *remote_file = remote_file;

        printf("开始上传文件...\n");
        printf("local_file: %s, remote_file: %s\n", local_file, remote_file);

        for (size_t i = 0; i < MAX_SSH; ++i) {
            if (my_ssh[i] == NULL) {
                printf("my_ssh[%zu] is empty\n", i);
            } else {
                printf("my_ssh[%zu] is in use (%p)\n", i, (void*)my_ssh[i]);
                rc = upload_file(my_ssh[i], local_file, remote_file);
                if (rc == SSH_OK) {
                    printf("文件node %zu 上传成功！\n", i);
                } else {
                    fprintf(stderr, "node %zu 上传失败: %s\n", i, ssh_get_error(my_ssh[i]));
                }
//                ssh_disconnect(my_ssh[i]);
//                ssh_free(my_ssh[i]);
            }
        }

        // 使用后必须释放
        free(local_file);
        free(remote_file);
    }



    // 清理资源
    for (size_t i = 0; i < MAX_SSH; ++i) {
        if (my_ssh[i] == NULL) {
            printf("my_ssh[%zu] is empty\n", i);
        } else {
            printf("my_ssh[%zu] is in use (%p)\n", i, (void*)my_ssh[i]);
            ssh_disconnect(my_ssh[i]);
            ssh_free(my_ssh[i]);
        }
    }



    return 0;
}
